import unittest, datetime
from parser import Parser, ParseError
from utils import TZInfo
from html5dt import *

class APITestCase(unittest.TestCase):

    def __init__(self, *args, **kwargs):
        super(APITestCase, self).__init__(*args, **kwargs)
        self.month_string_tests2 = ParserTestCase.month_string_tests2
        self.date_string_tests = ParserTestCase.date_string_tests
        self.time_string_tests = ParserTestCase.time_string_tests
        self.local_datetime_string_tests = \
                ParserTestCase.local_datetime_string_tests
        self.global_datetime_string_tests = \
                ParserTestCase.global_datetime_string_tests
        self.date_or_time_string_tests1 = \
                ParserTestCase.date_or_time_string_tests1
        self.date_or_time_string_tests2 = \
                ParserTestCase.date_or_time_string_tests2

    def _run_tests(self, func, tests, *args, **kwargs):

        for str, res, pos, err in tests:
            try:
                r = func(str, *args, **kwargs)
                if len(res) == 3:
                    self.assertTrue(r == datetime.date(*res))
                elif len(res) == 4:
                    self.assertTrue(r == datetime.time(*res))
                elif len(res) == 7:
                    year, month, day, hour, minute, s, us = res
                    self.assertTrue(r == datetime.datetime(year, month, 
                        day, hour, minute, s, us))
                else:
                    year, month, day, hour, minute, s, us, tz = res
                    tzinfo = TZInfo(*tz)
                    self.assertTrue(r == datetime.datetime(year, month, 
                        day, hour, minute, s, us, tzinfo))
            except ParseError, e:
                self.assertTrue(e._pos == pos and e._err == err)
            
    def test_date_string(self):
        self._run_tests(parse_date, self.date_string_tests)

    def test_time_string(self):
        self._run_tests(parse_time, self.time_string_tests)

    def test_local_datetime_string(self):
        self._run_tests(parse_local_datetime,
                self.local_datetime_string_tests)

    def test_global_datetime_string(self):
        self._run_tests(parse_global_datetime,
                self.global_datetime_string_tests)

    def test_date_or_time_string(self):
        self._run_tests(parse_date_or_time,
                self.date_or_time_string_tests1)
        self._run_tests(parse_date_or_time,
                self.date_or_time_string_tests2, in_content=True)

class ParserTestCase(unittest.TestCase):

    def _run_tests(self, meth, tests, *args, **kwargs):
        e = lambda e: e is None and '0' or e[0]

        for str, res, pos, err in tests:
            p = Parser(str)
            r = getattr(p, meth)(*args, **kwargs)
            self.assertTrue(r == res,
                    msg = "%s, %s/%s, %s/%s, %s/%s" % (str, res, r, 
                        pos, p._pos, e(err), e(p.err)))
            self.assertTrue(p._pos == pos, 
                    msg = "%s, %s/%s, %s/%s, %s/%s" % (str, res, r,
                        pos, p._pos, e(err), e(p.err)))
            self.assertTrue(p.err == err, 
                    msg = "%s, %s/%s, %s/%s, %s/%s" % (str, res, r,
                        pos, p._pos, e(err), e(p.err)))

    def test_month_component(self):        
        self._run_tests('parse_month_component', self.month_component_tests1)
        self._run_tests('parse_month_component', self.month_component_tests2)
        self._run_tests('parse_month_component', self.month_component_tests3)

    def test_date_component(self):
        self._run_tests('parse_date_component', self.date_component_tests)
        self._run_tests('parse_date_component', self.month_component_tests3)

    def test_time_component(self):
        self._run_tests('parse_time_component', self.time_component_tests1)
        self._run_tests('parse_time_component', self.time_component_tests2)

    def test_tz_component(self):
        self._run_tests('parse_timezone_component', self.tz_component_tests1)
        self._run_tests('parse_timezone_component', self.tz_component_tests2)

    def test_month_string(self):
        self._run_tests('parse_month_string', self.month_component_tests1)
        self._run_tests('parse_month_string', self.month_string_tests2)

    def test_date_string(self):
        self._run_tests('parse_date_string', self.date_string_tests)

    def test_time_string(self):
        self._run_tests('parse_time_string', self.time_string_tests)

    def test_local_datetime_string(self):
        self._run_tests('parse_local_datetime_string',
                self.local_datetime_string_tests)

    def test_global_datetime_string(self):
        self._run_tests('parse_global_datetime_string',
                self.global_datetime_string_tests)

    def test_date_or_time_string(self):
        self._run_tests('parse_date_or_time_string',
                self.date_or_time_string_tests1)
        self._run_tests('parse_date_or_time_string',
                self.date_or_time_string_tests2, in_content=True)

    month_component_tests1 = [
            ('0001-02', (1, 02), 7, None),
            ('2016-02', (2016, 02), 7, None),
            ('2016-03', (2016, 03), 7, None),
            ('2016-04', (2016, 04), 7, None),
            ('2016-05', (2016, 05), 7, None),
            ('2016-06', (2016, 06), 7, None),
            ('2016-07', (2016, 07), 7, None),
            ('2016-08', (2016, 8), 7, None),
            ('2016-09', (2016, 9), 7, None),
            ('2016-10', (2016, 10), 7, None),
            ('2016-11', (2016, 11), 7, None),
            ('2011-12', (2011, 12), 7, None),
            ('20123-03', (20123, 3), 8, None),
            ]

    month_component_tests2 = [
            ('0001-02a', (1, 02), 7, None),
            ('2016-02a', (2016, 02), 7, None),
            ('2016-03a', (2016, 03), 7, None),
            ('2016-04a', (2016, 04), 7, None),
            ('2016-05a', (2016, 05), 7, None),
            ('2016-06a', (2016, 06), 7, None),
            ('2016-07a', (2016, 07), 7, None),
            ('2016-08a', (2016, 8), 7, None),
            ('2016-09a', (2016, 9), 7, None),
            ('2016-10a', (2016, 10), 7, None),
            ('2016-11a', (2016, 11), 7, None),
            ('2011-12a', (2011, 12), 7, None),
            ('20123-03a', (20123, 3), 8, None),
            ]
    month_component_tests3 = [
            ('', None, 0, Parser.Errors.no_year_err),
            (' ', None, 0, Parser.Errors.no_year_err),
            ('1', None, 1, Parser.Errors.no_year_err),
            ('12', None, 2, Parser.Errors.no_year_err),
            ('123', None, 3, Parser.Errors.no_year_err),
            ('1244', None, 4, Parser.Errors.hyphen_expected_err),
            ('-', None, 0, Parser.Errors.no_year_err),
            ('1-', None, 1, Parser.Errors.no_year_err),
            ('12-', None, 2, Parser.Errors.no_year_err),
            ('123-', None, 3, Parser.Errors.no_year_err),
            ('1244-', None, 5, Parser.Errors.no_month_err),
            ('a', None, 0, Parser.Errors.no_year_err),
            ('1a', None, 1, Parser.Errors.no_year_err),
            ('12a', None, 2, Parser.Errors.no_year_err),
            ('123c', None, 3, Parser.Errors.no_year_err),
            ('1244d', None, 4, Parser.Errors.hyphen_expected_err),
            ('a', None, 0, Parser.Errors.no_year_err),
            ('a1a', None, 0, Parser.Errors.no_year_err),
            ('b12a', None, 0, Parser.Errors.no_year_err),
            ('c123c', None, 0, Parser.Errors.no_year_err),
            ('d1244d', None, 0, Parser.Errors.no_year_err),
            ('2-12', None, 1, Parser.Errors.no_year_err),
            ('22-12', None, 2, Parser.Errors.no_year_err),
            ('222-12', None, 3, Parser.Errors.no_year_err),
            ('2222-00', None, 7, Parser.Errors.no_month_err),
            ('22223-13', None, 8, Parser.Errors.no_month_err),
            ('2222-0', None, 6, Parser.Errors.no_month_err),
            ('2222-1', None, 6, Parser.Errors.no_month_err),
            ('2222-1a', None, 6, Parser.Errors.no_month_err),
            ('2222-121b', None, 8, Parser.Errors.no_month_err),
            ('2222-121', None, 8, Parser.Errors.no_month_err),
            ]

    month_string_tests2 = [
            ('0001-02a', None, 7, Parser.Errors.eos_expected_err),
            ]

    date_component_tests = [
            ('2011-01-01', (2011, 01, 01), 10, None),
            ('2011-01-01a', (2011, 01, 01), 10, None),

            ('2011-01', None, 7, Parser.Errors.hyphen_expected_err),
            ('2011-01a12', None, 7, Parser.Errors.hyphen_expected_err),
            ('2011-01-', None, 8, Parser.Errors.no_day_err),
            ('2011-01-a', None, 8, Parser.Errors.no_day_err),
            ('2011-01-1', None, 9, Parser.Errors.no_day_err),
            ('2011-01-00', None, 10, Parser.Errors.no_day_err),
            ('2011-01-32', None, 10, Parser.Errors.no_day_err),
            ('2011-01-123', None, 11, Parser.Errors.no_day_err),
            ('2011-01-1a', None, 9, Parser.Errors.no_day_err),
            ('2011-01-00a', None, 10, Parser.Errors.no_day_err),
            ('2011-01-32a', None, 10, Parser.Errors.no_day_err),
            ('2011-01-123a', None, 11, Parser.Errors.no_day_err),

            ]

    date_string_tests = [
            ('2011-01-01', (2011, 01, 01), 10, None),
            ('2011-01-01a', None, 10, Parser.Errors.eos_expected_err),
            ]

    time_component_tests1 = [
            ('16:12', (16, 12, 0, 0), 5, None),
            ('23:59:59', (23, 59, 59, 0), 8, None),
            ('00:00:00.9', (0, 0, 0, 900000), 10, None),
            ('16:12a', (16, 12, 0, 0), 5, None),
            ('23:59:59b', (23, 59, 59, 0), 8, None),
            ('00:00:00.9c', (0, 0, 0, 900000), 10, None),
            ('00:00:00.901c', (0, 0, 0, 901000), 12, None),
            ]

    time_component_tests2 = [
            ('', None, 0, Parser.Errors.no_hour_err),
            ('a', None, 0, Parser.Errors.no_hour_err),
            ('0', None, 1, Parser.Errors.no_hour_err),
            ('24', None, 2, Parser.Errors.no_hour_err),
            ('24a', None, 2, Parser.Errors.no_hour_err),
            ('220', None, 3, Parser.Errors.no_hour_err),
            ('22a', None, 2, Parser.Errors.colon_expected_err),
            ('22:', None, 3, Parser.Errors.no_minute_err),
            ('22:0', None, 4, Parser.Errors.no_minute_err),
            ('22:60', None, 5, Parser.Errors.no_minute_err),
            ('22:122', None, 6, Parser.Errors.no_minute_err),
            ('22:12:a', None, 6, Parser.Errors.no_secs_err),
            ('22:12:2', None, 6, Parser.Errors.no_secs_err),
            ('22:12:2a', None, 6, Parser.Errors.no_secs_err),
            ('22:12:2.', None, 6, Parser.Errors.no_secs_err),
            ('22:12:23.', None, 9, Parser.Errors.no_secs_err),
            ('22:12:23..', None, 10, Parser.Errors.no_secs_err),
            ('22:12:23.2.', None, 11, Parser.Errors.no_secs_err),
            ('22:12:23.22.', None, 12, Parser.Errors.no_secs_err),
            ('22:12:60', None, 8, Parser.Errors.no_secs_err),
            ('22:12:60.1', None, 10, Parser.Errors.no_secs_err),
            ]

    time_string_tests = [
            ('16:12', (16, 12, 0, 0), 5, None),
            ('23:59:59', (23, 59, 59, 0), 8, None),
            ('00:00:00.9', (0, 0, 0, 900000), 10, None),
            ('16:12a', None, 5, Parser.Errors.eos_expected_err),
            ('23:59:59b', None, 8, Parser.Errors.eos_expected_err),
            ('00:00:00.9c', None, 10, Parser.Errors.eos_expected_err),
            ('00:00:00.901 ', None, 12, Parser.Errors.eos_expected_err),
            ]
    tz_component_tests1 = [
            ('Z', (0,0,0), 1, None),
            ('+12:12', (12,12,1), 6, None),
            ('-12:12', (12,12,-1), 6, None),
            ('Za', (0,0,0), 1, None),
            ('+00:00a', (00,00,1), 6, None),
            ('-23:59a', (23,59,-1), 6, None),
            ]

    tz_component_tests2 = [
            ('A', None, 0, Parser.Errors.z_expected_err),
            ('A23:00', None, 0, Parser.Errors.z_expected_err),
            ('-2:00', None, 2, Parser.Errors.no_tz_hours_err),
            ('-a24:00', None, 1, Parser.Errors.no_tz_hours_err),
            ('-24:00', None, 3, Parser.Errors.no_tz_hours_err),
            ('+230:00', None, 4, Parser.Errors.no_tz_hours_err),
            ('+23a00', None, 3, Parser.Errors.colon_expected_err),
            ('+23:a00', None, 4, Parser.Errors.no_tz_minutes_err),
            ('+23:0', None, 5, Parser.Errors.no_tz_minutes_err),
            ('+23:0a', None, 5, Parser.Errors.no_tz_minutes_err),
            ('+23:000', None, 7, Parser.Errors.no_tz_minutes_err),
            ('+23:60', None, 6, Parser.Errors.no_tz_minutes_err),
            ('+23:60a', None, 6, Parser.Errors.no_tz_minutes_err),
            ]

    local_datetime_string_tests = [
            ('2011-01-01T11:23', (2011, 1, 1, 11, 23, 0, 0), 16, None),
            ('2011-01-01T11:23 ', None, 16, Parser.Errors.eos_expected_err),
            ('2011-01-01', None, 10, Parser.Errors.t_expected_err),
            ('2011-01-01 ', None, 10, Parser.Errors.t_expected_err),
            ('2011-01-01T', None, 11, Parser.Errors.no_hour_err),
            ('2011-01-01T ', None, 11, Parser.Errors.no_hour_err),
            ]

    global_datetime_string_tests = [
            ('2011-01-01T11:23Z', (2011, 1, 1, 11, 23, 0, 0, (0, 0, 0)), 
                17, None),
            ('2011-01-01T11:23+12:12', (2011, 1, 1, 11, 23, 0, 0, (12, 12, 1)), 
                22, None),
            ('2011-01-01T11:23Z ', None, 17, Parser.Errors.eos_expected_err),
            ('2011-01-01T11:23+12:12 ', None, 22, 
                Parser.Errors.eos_expected_err),
            ('2011-01-01T11:23', None, 16, Parser.Errors.z_expected_err),
            ('2011-01-01T11:23 ', None, 16, Parser.Errors.z_expected_err),
            ('2011-01-01', None, 10, Parser.Errors.t_expected_err),
            ('2011-01-01 ', None, 10, Parser.Errors.t_expected_err),
            ('2011-01-01T', None, 11, Parser.Errors.no_hour_err),
            ('2011-01-01T ', None, 11, Parser.Errors.no_hour_err),
            ]

    date_or_time_string_tests1 = [
            ('2011-01-01T11:23Z', (2011, 1, 1, 11, 23, 0, 0, (0, 0, 0)), 
                17, None),
            ('2011-01-01T11:23+12:12', (2011, 1, 1, 11, 23, 0, 0, (12, 12, 1)), 
                22, None),
            ('16:12', (16, 12, 0, 0), 5, None),
            ('23:59:59', (23, 59, 59, 0), 8, None),
            ('00:00:00.9', (0, 0, 0, 900000), 10, None),
            ('2011-01-01', (2011, 01, 01), 10, None),
            ('2011-01-01T', None, 11, Parser.Errors.no_hour_err),
            ('2011-01-01T11:23', None, 16, Parser.Errors.z_expected_err),
            ('2011-01-01T11:23 ', None, 16, Parser.Errors.z_expected_err),

            ('2011-01-01 ', None, 10, Parser.Errors.eos_expected_err),
            ('16:12a', None, 5, Parser.Errors.eos_expected_err),
            ('2011-01-01T11:23Z ', None, 17, Parser.Errors.eos_expected_err),
            ]

    date_or_time_string_tests2 = [
            (u'\t2011-01-01T11:23Z ', (2011, 1, 1, 11, 23, 0, 0, (0, 0, 0)), 
                19, None),
            (u'\t\t2011-01-01T11:23+12:12\t\n\r', 
                (2011, 1, 1, 11, 23, 0, 0, (12, 12, 1)), 27, None),
            (u'\t16:12\t', (16, 12, 0, 0), 7, None),
            (u'  23:59:59 ', (23, 59, 59, 0), 11, None),
            (u' 16:12 a', None, 7, Parser.Errors.eos_expected_err),
            ]
